package com.bianmaba.services.datacollection.quartiz;

import com.bianmaba.beans.datacollection.CollectionSchedule;
import com.bianmaba.beans.datacollection.CollectionTask;
import com.bianmaba.beans.datacollection.ExecuteLog;
import com.bianmaba.beans.datacollection.TaskInstance;
import com.bianmaba.commons.bean.result.OperationResult;
import com.bianmaba.dc.bean.JobParameter;
import com.bianmaba.dc.bean.TaskStatus;
import com.bianmaba.dc.bean.TaskType;
import com.bianmaba.remote.IterationService;
import com.bianmaba.remote.MemberService;
import com.bianmaba.remote.ProjectService;
import com.bianmaba.services.datacollection.ExecuteLogRecorder;
import com.bianmaba.services.datacollection.ICollectionScheduleService;
import com.bianmaba.services.datacollection.ICollectionTaskService;
import com.bianmaba.services.datacollection.ITaskInstanceService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.*;


@Component
@Transactional
public class GlobalJobListener implements org.quartz.JobListener {
    @Autowired
    private ITaskInstanceService taskInstanceService;
    @Autowired
    private ICollectionTaskService collectionTaskService;
    @Autowired
    private ICollectionScheduleService collectionScheduleService;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private IterationService iterationService;

    @Autowired
    private ExecuteLogRecorder logWriter;

    private static Logger logger = LoggerFactory.getLogger(GlobalJobListener.class);

    @Override
    public String getName() {
        String name = getClass().getSimpleName();
        logger.info(" listener name is:" + name);
        return name;
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        JobDataMap jobDatas = context.getMergedJobDataMap();

        Object taskType = jobDatas.get(JobParameter.TASK_TYPE.getName());
        if (TaskType.DATA_COLLECTION_TASK.equals(taskType)) {
            List<String> messages = new ArrayList<>(0);
            messages.add("准备执行采集JOB...");
            jobDatas.put("messages", messages);
            logger.info("检查采集JOB数据。");
            //检查数据参数，如果参数错误存在错误则不创建实例
            List<String> errors = checkCollectionJobDatas(jobDatas);
            if (errors.isEmpty()) {
                logger.info("JOB数据正确。");
                messages.add("准备初始化采集JOB。");
                initCollectionJob(jobDatas, messages);
            } else {
                logger.error("采集JOB数据缺失:" + "\r\n" + StringUtils.joinWith("\r\n", errors));
            }
        } else if (TaskType.DATA_COLLECTION_TASK_STATUS_CHECK.equals(taskType)) {
            logger.info("准备执行数据采集任务状态监听：" + jobDatas.getWrappedMap().toString());

        } else {
            logger.info("准备执行JOB：" + jobDatas.getWrappedMap().toString());
        }
    }

    private void initCollectionJob(JobDataMap jobDatas, List<String> messages) {
        TaskInstance taskInstance;//准备数据并创建任务实例
        String taskId = jobDatas.getString(JobParameter.TASK_ID.getName());
        CollectionTask task = collectionTaskService.getById(taskId);
        CollectionSchedule schedule = null;


        String scheduleId = jobDatas.getString(JobParameter.SCHEDULE_ID.getName());
        if (StringUtils.isNotEmpty(scheduleId)) {
            schedule = collectionScheduleService.getById(scheduleId);
        }
        String executor = jobDatas.getString(JobParameter.EXECUTOR.getName());
        messages.add("准备创建任务实例...");
        taskInstance = taskInstanceService.createTaskInstance(schedule, task, executor);

        //补充采集相关参数
        jobDatas.put(JobParameter.TASK_INSTANCE_ID.getName(), taskInstance.getId());

        if (taskInstance != null) {
            messages.add("任务实例创建完成：" + taskInstance.getId());
            //处理参数

            messages.add("处理采集参数...");
            Map<String, String> parameterParts = processingParameters(task.getProjectId(), (List<Map<String, String>>) jobDatas.get(JobParameter.COLLECTION_PARAMETERS.getName()), messages, jobDatas);
            if (jobDatas.containsKey("inited") && !jobDatas.getBoolean("inited")) {
                return;
            }
            jobDatas.put(JobParameter.COLLECTION_PARAMETER_PARTS.getName(), parameterParts);

            messages.add("采集参数处理完成。");
            jobDatas.put("inited", true);
        } else {
            logger.error("任务实例创建失败。");
            jobDatas.put("inited", false);
        }
    }

    private List<String> checkCollectionJobDatas(JobDataMap jobDatas) {
        List<String> errors = new ArrayList<>(0);
        Map<String, Object> map = jobDatas.getWrappedMap();
        if (map.get(JobParameter.TASK_TYPE.getName()) == null) {
            errors.add("采集任务JOB数据中缺少任务类型");
        }
        if (map.get(JobParameter.PROJECT_ID.getName()) == null) {
            errors.add("采集任务JOB数据中缺少项目编号");
        }
        if (map.get(JobParameter.TASK_ID.getName()) == null) {
            errors.add("采集任务JOB数据中缺少任务编号");
        }
        if (map.get(JobParameter.EXECUTOR.getName()) == null) {
            errors.add("采集任务JOB数据中缺少执行人");
        }
        return errors;
    }

    private Map<String, String> processingParameters(String projectNo, List<Map<String, String>> parameters, List<String> messages, JobDataMap jobDatas) {
        Map<String, String> parameterParts = new HashMap<>();
        Map<String, Object> project = null;
        Map<String, Object> iteration = null;
        Map<String, String> overwriteValues = (Map<String, String>) jobDatas.get("overwrite_values");
        if (parameters != null) {
            for (Map<String, String> map : parameters) {
                if (map.containsKey("name")) {
                    String value = map.get("value");
                    //判断参数数据来源
                    if (map.containsKey("inputType") && map.get("inputType") != null && StringUtils.isEmpty(map.get("value"))) {
                        String inputType = map.get("inputType");
                        //如果是项目编号则直接赋值后结束当前循环
                        if ("项目编号".equalsIgnoreCase(inputType)) {
                            value = projectNo;
                            parameterParts.put(map.get("name"), value);
                            continue;
                        }
                        if ("当日".equalsIgnoreCase(inputType)) {
                            value = DateFormatUtils.format(Calendar.getInstance().getTime(), "yyyy-MM-dd HH:mm:ss");
                            parameterParts.put(map.get("name"), value);
                            continue;
                        }
                        if (inputType.contains("项目")) {
                            if (project == null) {
                                OperationResult<Map> result = projectService.getByNo(projectNo);
                                project = result.getData();
                            }
                            if (project == null) {
                                messages.add("项目信息不存在，部份采集参数无法获取。");
                                jobDatas.put("inited", false);
                                return null;
                            }
                            if ("项目名称".equalsIgnoreCase(inputType)) {
                                value = project.getOrDefault("name", "").toString();
                            } else if ("项目开始时间".equalsIgnoreCase(inputType)) {
                                String key = "startDate";
                                if (overwriteValues.containsKey(key)) {
                                    value = overwriteValues.get(key);
                                } else {
                                    value = project.getOrDefault("startStr", "").toString();
                                }
                            } else if ("项目结束时间".equalsIgnoreCase(inputType)) {
                                String key = "endDate";
                                if (overwriteValues.containsKey(key)) {
                                    value = overwriteValues.get(key);
                                } else {
                                    value = project.getOrDefault("endStr", "").toString();
                                }
                            } else if ("项目人员".equalsIgnoreCase(inputType)) {
                                OperationResult<Map> result = memberService.listByNo(projectNo);
                                if (!result.isSuccess() || result.getData() != null) {
                                    List<Map<String, Object>> members = (List<Map<String, Object>>) result.getData();
                                    if (members != null && !members.isEmpty()) {
                                        List<String> users = new ArrayList<>(0);
                                        for (Map<String, Object> item : members) {
                                            String acc = (String) item.getOrDefault("zrAccount", "");
                                            if (acc != null && StringUtils.isNotEmpty(acc.trim())) {
                                                users.add(acc.trim());
                                            }
                                        }
                                        if (!users.isEmpty()) {
                                            value = StringUtils.joinWith(",", users.toArray(new String[users.size()]));
                                        }
                                    }
                                }
                            }
                        } else if (inputType.contains("迭代")) {
                            if (iteration == null) {
                                OperationResult<Map> result = null;
                                try {
                                    result = iterationService.getByProjectNoAndDatetime(projectNo, DateUtils.parseDate("2019-01-06", "yyyy-MM-dd"));
                                } catch (ParseException e) {
                                    messages.add("迭代信息获取失败，部份采集参数无法初始化。");
                                    jobDatas.put("inited", false);
                                    return null;
                                }
                                iteration = result.getData();
                            }
                            if (iteration == null) {
                                messages.add("迭代信息不存在，部份采集参数无法获取。");
                                jobDatas.put("inited", false);
                                return null;
                            }
                            if ("迭代名称".equalsIgnoreCase(inputType)) {
                                value = iteration.getOrDefault("iteName", "").toString();
                            } else if ("迭代开始时间".equalsIgnoreCase(inputType)) {
                                String key = "startDate";
                                if (overwriteValues.containsKey(key)) {
                                    value = overwriteValues.get(key);
                                } else {
                                    Object startDate = iteration.getOrDefault(key, "");
                                    if (startDate != null) {
                                        value = DateFormatUtils.format(new Date((Long) startDate), "yyyy-MM-dd");
                                    }
                                }
                            } else if ("迭代结束时间".equalsIgnoreCase(inputType)) {
                                String key = "endDate";
                                if (overwriteValues.containsKey(key)) {
                                    value = overwriteValues.get(key);
                                } else {
                                    Object endDate = iteration.getOrDefault(key, "");
                                    if (endDate != null) {
                                        value = DateFormatUtils.format(new Date((Long) endDate), "yyyy-MM-dd");
                                    }
                                }
                            }
                        }
                        if (StringUtils.isEmpty(value)) {
                            messages.add("采集参数无法获取：" + map.get("name") + "。");
                            jobDatas.put("inited", false);
                            return null;
                        }
                    }
                    parameterParts.put(map.get("name"), value);
                }
            }
        }
        return parameterParts;
    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
        String jobName = context.getJobDetail().getKey().getName();
        logger.info("JOB执行被否决：" + jobName);
    }

    /**
     * JOB执行完成的处理函数，如果异常时需要更新任务实例的状态
     *
     * @param context
     * @param jobException
     */
    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        JobDataMap dataMap = context.getMergedJobDataMap();
        String taskInstanceId = dataMap.getString(JobParameter.TASK_INSTANCE_ID.getName());
        Object taskType = dataMap.get(JobParameter.TASK_TYPE.getName());
        if (jobException != null) {
            String error = "JOB执行异常：" + dataMap.getWrappedMap().toString();
            logger.info(error);
            if (taskInstanceId != null) {
                Integer status = TaskStatus.EXCEPTIONAL.getIndex();
                taskInstanceService.updateStatus(taskInstanceId, status);
                logWriter.put(ExecuteLog.of(taskInstanceId, error, new Date()));
            }
        } else if (dataMap.containsKey("inited") && !dataMap.getBoolean("inited")) {
            logger.error("JOB初始化出现错误，终止执行：" + dataMap.getWrappedMap().toString());
        } else {

            if (TaskType.DATA_COLLECTION_TASK.equals(taskType)) {
                logger.info("采集任务已经提交采集器，开始监听采集状态");
                taskInstanceService.startStatusCheck(taskInstanceId);
            } else if (TaskType.DATA_COLLECTION_TASK_STATUS_CHECK.equals(taskType)) {
                logger.info("采集任务状态监听结束：" + dataMap.getWrappedMap().toString());
            } else {
                logger.info("JOB执行结束：" + dataMap.getWrappedMap().toString());
            }
        }
    }
}